using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Globalization;


namespace D3crft.Windows.UserControls {

    public class ItemDPSEventArgs : EventArgs {
        public float fBaseDPS = 0.0f;
        public float fItemDPS = 0.0f;
    }

    public partial class ucItemEditor : UserControl {

        public delegate void delAddStatHandler(object oSender, ucItemEditor.delStatReturnHandler oReturnHandler);
        public delegate void delEditStatHandler(object oSender, int iStatID, float fStatAmmount, int iStatIndex, ucItemEditor.delStatReturnHandler oReturnHandler);
        public delegate void ItemDPSHandler(object oSender, ItemDPSEventArgs eaItemDPS);
        public delegate void delStatReturnHandler(bool bCanceled, int iStatID, float fStatAmmount, int iStatIndex);

        public event delAddStatHandler evAddClicked; // rework!
        public event delEditStatHandler evStatClicked; // rework!
        public event ItemDPSHandler evItemStatsChanged; 
        public event Characters.ClassObjects.ocCharacter.CharacterEventHandler evNonItemizedCharacterChanged;

        private List<float> lItemDPS;
        private List<Label> lItemDPSLabels;
        private List<float> lItemStatAmmounts;
        private List<int> lItemStatIDs;
        private List<Label> lItemStatLabels;
        private List<Image> lItemCloseImages;
        private Characters.ClassObjects.ocCharacter oSelectedCharacter;
        private Characters.ClassObjects.ocCharacter oNonItemizedCharacter;
        private bool bIsEquipped;
        private float fBaseDPS;
        private float fItemDPS;

        public ucItemEditor() {
            do_Initialize();
            do_Preset();
            do_StartUp();
        }

        private void do_Initialize() {
            this.InitializeComponent();
            this.lItemStatIDs = new List<int>();
            this.lItemStatLabels = new List<Label>();
            this.lItemStatAmmounts = new List<float>();
            this.lItemDPS = new List<float>();
            this.lItemDPSLabels = new List<Label>();
            this.lItemCloseImages = new List<Image>();
        }

        private void do_Preset() {
            bIsEquipped = true;
            fItemDPS = 0.0f;

            this.UserControl_Add.MouseEnter += new MouseEventHandler(this.ev_oAdd_MouseEnter);
            this.UserControl_Add.MouseLeave += new MouseEventHandler(this.ev_oAdd_MouseLeave);
            this.Check_Equipped.evCheckedChanged += new EventHandler(ev_oEquippedCheckBox_CheckedChanged);
        }

        private void do_StartUp() {
            this.do_RePositionAddLabel();
        }

        private void do_AddNewStat(int iStatID, float fStatAmmount) {
            Label item = new Label();
            Label label2 = new Label();
            Image oCloseImage = new Image();
            item.VerticalAlignment = VerticalAlignment.Top;
            item.HorizontalAlignment = HorizontalAlignment.Left;
            item.Margin = new Thickness(30.0, 64.0 + (this.lItemStatIDs.Count * 20.0), 0.0, 0.0);
            item.Height = 24.0;
            item.Width = 160.0;
            item.Content = "+" + fStatAmmount.ToString() + " " + Stats.scStatFunctions.GetStatNameByID(iStatID);
            item.Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
            item.MouseEnter += new MouseEventHandler(this.ev_LinkLabel_MouseEnter);
            item.MouseLeave += new MouseEventHandler(this.ev_LinkLabel_MouseLeave);
            item.MouseUp += new MouseButtonEventHandler(this.ev_LinkLabel_MouseUp);
            label2.VerticalAlignment = VerticalAlignment.Top;
            label2.HorizontalAlignment = HorizontalAlignment.Right;
            label2.Margin = new Thickness(0.0, 64.0 + (this.lItemStatIDs.Count * 20.0), 163.0, 0.0);
            label2.Height = 24.0;
            label2.Width = 75.0;
            label2.Content = "n/A";
            label2.HorizontalContentAlignment = HorizontalAlignment.Right;
            oCloseImage.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            oCloseImage.VerticalAlignment = System.Windows.VerticalAlignment.Top;
            oCloseImage.Margin = new Thickness(16, 71.0 + (this.lItemStatIDs.Count * 20.0), 0, 0);
            oCloseImage.Width = 12;
            oCloseImage.Height = 12;
            oCloseImage.Source = new BitmapImage(new Uri("pack://application:,,,/D3Crft;component/images/icon_characterchooser_close_normal.png", UriKind.Absolute));
            oCloseImage.MouseUp += new MouseButtonEventHandler(ev_oCloseImage_MouseUp);
            this.lItemStatIDs.Add(iStatID);
            this.lItemStatLabels.Add(item);
            this.lItemStatAmmounts.Add(fStatAmmount);
            this.lItemDPS.Add(0f);
            this.lItemDPSLabels.Add(label2);
            this.lItemCloseImages.Add(oCloseImage);
            this.Grid_Main.Children.Add(item);
            this.Grid_Main.Children.Add(label2);
            this.Grid_Main.Children.Add(oCloseImage);
            this.do_RepositionAllStats();
            this.do_RePositionAddLabel();
            this.do_RecalculateDPS(this.lItemStatIDs.Count - 1);
            this.do_RecalulateOverallDPS();
            if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
            if (bIsEquipped) if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
        }

        private bool do_EditStat(int iStatIndex, int iStatID, float fStatAmmount) {
            if (this.lItemStatIDs.Count > iStatIndex) {
                this.lItemStatIDs[iStatIndex] = iStatID;
                this.lItemStatLabels[iStatIndex].Content = "+" + fStatAmmount.ToString() + " " + Stats.scStatFunctions.GetStatNameByID(iStatID);
                this.lItemStatAmmounts[iStatIndex] = fStatAmmount;
                this.do_RecalculateDPS(iStatIndex);
                this.do_RecalulateOverallDPS();
                if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
                if (bIsEquipped) if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
                return true;
            }
            return false;
        }

        private bool do_RemoveStat(int iStatIndex) {
            if (this.lItemStatIDs.Count > iStatIndex) {
                this.Grid_Main.Children.Remove(this.lItemStatLabels[iStatIndex]);
                this.Grid_Main.Children.Remove(this.lItemDPSLabels[iStatIndex]);
                this.Grid_Main.Children.Remove(this.lItemCloseImages[iStatIndex]);
                this.lItemStatIDs.RemoveAt(iStatIndex);
                this.lItemStatLabels.RemoveAt(iStatIndex);
                this.lItemStatAmmounts.RemoveAt(iStatIndex);
                this.lItemDPS.RemoveAt(iStatIndex);
                this.lItemDPSLabels.RemoveAt(iStatIndex);
                this.lItemCloseImages.RemoveAt(iStatIndex);
                do_RepositionAllStats();
                this.do_RePositionAddLabel();
                this.do_RecalulateOverallDPS();
                if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
                if (bIsEquipped) if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
                return true;
            }
            return false;
        }

        private void do_ClearAllStats() {
            while (this.lItemStatIDs.Count > 0) {
                this.Grid_Main.Children.Remove(this.lItemStatLabels[0]);
                this.Grid_Main.Children.Remove(this.lItemDPSLabels[0]);
                this.Grid_Main.Children.Remove(this.lItemCloseImages[0]);
                this.lItemStatIDs.RemoveAt(0);
                this.lItemStatLabels.RemoveAt(0);
                this.lItemStatAmmounts.RemoveAt(0);
                this.lItemDPS.RemoveAt(0);
                this.lItemDPSLabels.RemoveAt(0);
                this.lItemCloseImages.RemoveAt(0);
            }
            this.do_RePositionAddLabel();
            this.do_RecalulateOverallDPS();
            if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
            if (bIsEquipped) if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
        }

        private void do_RecalculateDPS(int iStatIndex) {
            Characters.ClassObjects.ocCharacter oCharacter;
            float fTemp;

            if (bIsEquipped) {
                oCharacter = Stats.scStatFunctions.GetStatChangedCharacter(this.oSelectedCharacter, this.lItemStatIDs[iStatIndex], this.lItemStatAmmounts[iStatIndex], Stats.scStatFunctions.eStatEditMode.Substract, Stats.scStatFunctions.eStatCharacterMode.CreateCharacterCopy);
                this.lItemDPS[iStatIndex] = Analysis.scCharacterAnalysis.GetCharacterDPS(this.oSelectedCharacter) - Analysis.scCharacterAnalysis.GetCharacterDPS(oCharacter);
                fTemp = this.lItemDPS[iStatIndex] / 1000.0f;
                this.lItemDPSLabels[iStatIndex].Content = fTemp.ToString("N1", CultureInfo.InvariantCulture).Replace(",", "") + "k";
            }
            else {
                oCharacter = Stats.scStatFunctions.GetStatChangedCharacter(this.oNonItemizedCharacter, this.lItemStatIDs[iStatIndex], this.lItemStatAmmounts[iStatIndex], Stats.scStatFunctions.eStatEditMode.Add, Stats.scStatFunctions.eStatCharacterMode.CreateCharacterCopy);
                this.lItemDPS[iStatIndex] = Analysis.scCharacterAnalysis.GetCharacterDPS(oCharacter) - Analysis.scCharacterAnalysis.GetCharacterDPS(oNonItemizedCharacter);
                fTemp = this.lItemDPS[iStatIndex] / 1000.0f;
                this.lItemDPSLabels[iStatIndex].Content = fTemp.ToString("N1", CultureInfo.InvariantCulture).Replace(",", "") + "k";
            }


        }

        private void do_RecalulateOverallDPS() {
            if (bIsEquipped) {
                if (oSelectedCharacter == null) return;
                Characters.ClassObjects.ocCharacter oCharacter = oSelectedCharacter.GetCopy();
                for (int i = 0; i < lItemStatIDs.Count; i++) {
                    oCharacter = Stats.scStatFunctions.GetStatChangedCharacter(oCharacter, this.lItemStatIDs[i], this.lItemStatAmmounts[i], Stats.scStatFunctions.eStatEditMode.Substract, Stats.scStatFunctions.eStatCharacterMode.EditCharacter);
                }
                fBaseDPS = Analysis.scCharacterAnalysis.GetCharacterDPS(oCharacter);
                fItemDPS = Analysis.scCharacterAnalysis.GetCharacterDPS(this.oSelectedCharacter) - fBaseDPS;
                this.do_RedrawChart();
            }
            else {
                if (oNonItemizedCharacter == null) return;
                Characters.ClassObjects.ocCharacter oCharacter = oNonItemizedCharacter.GetCopy();
                for (int i = 0; i < lItemStatIDs.Count; i++) {
                    oCharacter = Stats.scStatFunctions.GetStatChangedCharacter(oCharacter, this.lItemStatIDs[i], this.lItemStatAmmounts[i], Stats.scStatFunctions.eStatEditMode.Add, Stats.scStatFunctions.eStatCharacterMode.EditCharacter);
                }
                fBaseDPS = Analysis.scCharacterAnalysis.GetCharacterDPS(oNonItemizedCharacter);
                fItemDPS = Analysis.scCharacterAnalysis.GetCharacterDPS(oCharacter) - fBaseDPS;
                this.do_RedrawChart();
            }

        }

        private void do_RecalculateAllDPS() {
            for (int i = 0; i < lItemStatIDs.Count; i++) {
                do_RecalculateDPS(i);
            }
            do_RecalulateOverallDPS();
        }

        private void do_RedrawChart() {
            DrawingGroup oGroup = new DrawingGroup();
            GeometryDrawing oDrawing;
            float fMaxDPS = -0.1f;
            int iMaxIndex = 0;


            if (lItemStatIDs.Count > 0) {
                oDrawing = new GeometryDrawing();
                oDrawing.Pen = new Pen(this.FindResource("Brush_BarEndings") as Brush, 1.0);
                oDrawing.Geometry = new LineGeometry(new Point(0.0, 0.0), new Point(0.0, 15.0 + ((lItemStatIDs.Count - 1) * 16.0)));
                oGroup.Children.Add(oDrawing);
            }

            for (int i = 0; i < lItemDPS.Count; i++) {
                if (lItemDPS[i] > fMaxDPS) {
                    fMaxDPS = lItemDPS[i];
                    iMaxIndex = i;
                }
            }

            for (int i = 0; i < lItemStatIDs.Count; i++) {
                oDrawing = new GeometryDrawing();

                if (i == iMaxIndex) {
                    oDrawing.Pen = new Pen(base.FindResource("Gradient_BarHighlighted") as Brush, 7.0);
                    oDrawing.Geometry = new LineGeometry(new Point(0.0, 7.0 + ((double)i * 16.0)), new Point(100.0, 7.0 + ((double)i * 16.0)));
                }
                else {
                    oDrawing.Pen = new Pen(base.FindResource("Gradient_BarNormal") as Brush, 7.0);
                    oDrawing.Geometry = new LineGeometry(new Point(0.0, 7.0 + ((double)i * 16.0)), new Point((lItemDPS[i] / fMaxDPS) * 100.0, 7.0 + ((double)i * 16.0)));
                }
                oGroup.Children.Add(oDrawing);


                oDrawing = new GeometryDrawing();
                oDrawing.Pen = new Pen(base.FindResource("Brush_BarEndings") as Brush, 1.0);
                oDrawing.Geometry = new LineGeometry(new Point((lItemDPS[i] / fMaxDPS) * 100.0, 2.0 + ((double)i * 16.0)), new Point((lItemDPS[i] / fMaxDPS) * 100.0, 13.0 + ((double)i * 16.0)));
                oGroup.Children.Add(oDrawing);
            }

            this.Image_Chart.Source = new DrawingImage(oGroup);
        }

        private void do_RepositionAllStats() {
            for (int i = 0; i < lItemStatIDs.Count; i++) {
                lItemStatLabels[i].Margin = new Thickness(30.0, 64.0 + (i * 20.0), 0.0, 0.0);
                lItemDPSLabels[i].Margin = new Thickness(0.0, 64.0 + (i * 20.0), 163.0, 0.0);
                lItemCloseImages[i].Margin = new Thickness(16, 71.0 + (i * 20.0), 0, 0);
            }
        }

        private void do_RePositionAddLabel() {
            this.Grid_Add.Margin = new Thickness(10.0, 72.0 + (this.lItemStatIDs.Count * 20.0), 0.0, 0.0);
            if (this.lItemStatIDs.Count >= 7) {
                this.Grid_Add.Visibility = Visibility.Hidden;
            }
            else {
                this.Grid_Add.Visibility = Visibility.Visible;
            }
        }

        private int get_IndexByLabel(Label oLabel) {
            for (int i = 0; i < this.lItemStatLabels.Count; i++) {
                if (oLabel == this.lItemStatLabels[i]) {
                    return i;
                }
            }
            return -1;
        }

        private int get_IndexByImage(Image oImage) {
            for (int i = 0; i < this.lItemCloseImages.Count; i++) {
                if (oImage == this.lItemCloseImages[i]) {
                    return i;
                }
            }
            return -1;
        }

        private Characters.ClassObjects.ocCharacter do_CreateNewItemizedCharacter() {
            Characters.ClassObjects.ocCharacter oCharacter = oSelectedCharacter.GetCopy();

            for (int i = 0; i < lItemStatIDs.Count; i++) {
                oCharacter = Stats.scStatFunctions.GetStatChangedCharacter(oCharacter, lItemStatIDs[i], lItemStatAmmounts[i], Stats.scStatFunctions.eStatEditMode.Substract, Stats.scStatFunctions.eStatCharacterMode.EditCharacter);
            }
            return oCharacter;
        }

        private void ev_LinkLabel_MouseEnter(object sender, MouseEventArgs ea) {
            int iIndex = get_IndexByLabel(sender as Label);

            lItemStatLabels[iIndex].Foreground = this.FindResource("Brush_LinkHighlighted") as Brush;
            lItemDPSLabels[iIndex].Foreground = this.FindResource("Brush_LinkHighlighted") as Brush;
            base.Cursor = Cursors.Hand;
        }

        private void ev_LinkLabel_MouseLeave(object sender, MouseEventArgs ea) {
            int iIndex = get_IndexByLabel(sender as Label);

            lItemStatLabels[iIndex].Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
            lItemDPSLabels[iIndex].Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
            base.Cursor = Cursors.Arrow;
        }

        private void ev_LinkLabel_MouseUp(object sender, MouseButtonEventArgs ea) {
            if ((sender as Label).Name == "Label_Add") {
                this.evAddClicked(this, new delStatReturnHandler(this.ev_Object_ReturnHandler));
            }
            else {
                int iStatIndex = this.get_IndexByLabel(sender as Label);
                this.evStatClicked(this, this.lItemStatIDs[iStatIndex], this.lItemStatAmmounts[iStatIndex], iStatIndex, new delStatReturnHandler(this.ev_Object_ReturnHandler));
            }
        }

        private void ev_oAdd_MouseEnter(object sender, MouseEventArgs ea) {
            this.Border_Add.Background = Application.Current.FindResource("Gradient_HighlightedUC") as Brush;
        }

        private void ev_oAdd_MouseLeave(object sender, MouseEventArgs ea) {
            this.Border_Add.Background = Application.Current.FindResource("Gradient_DefaultUC") as Brush;
            this.Label_Add.Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
        }

        private void ev_oAdd_MouseDown(object sender, MouseEventArgs ea) {
            this.Border_Add.Background = Application.Current.FindResource("Gradient_PressedUC") as Brush;
            this.Label_Add.Foreground = Brushes.White;
        }

        private void ev_oAdd_MouseUp(object sender, MouseEventArgs ea) {
            this.Border_Add.Background = Application.Current.FindResource("Gradient_HighlightedUC") as Brush;
            this.Label_Add.Foreground = Application.Current.FindResource("Brush_DefaultForeground") as Brush;
            if (this.evAddClicked != null) {
                this.evAddClicked(this, new delStatReturnHandler(this.ev_Object_ReturnHandler));
            }
        }

        private void ev_Object_ReturnHandler(bool bCanceled, int iStatID, float fStatAmmount, int iStatIndex) {
            if (!bCanceled) {
                if (iStatIndex > -1) {
                    this.do_EditStat(iStatIndex, iStatID, fStatAmmount);
                }
                else {
                    this.do_AddNewStat(iStatID, fStatAmmount);
                }
            }
        }

        private void ev_oCloseImage_MouseUp(object sender, EventArgs ea) {
            int iIndex = get_IndexByImage(sender as Image);

            do_RemoveStat(iIndex);
        }

        private void ev_oEquippedCheckBox_CheckedChanged(object sender, EventArgs ea) {
            if (Check_Equipped.Checked) {
                bIsEquipped = true;
                do_RecalculateAllDPS();
                if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
                if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
            }
            else {
                Check_Equipped.RevertChecked();
            }
        }

        public void SetCharacter(Characters.ClassObjects.ocCharacter oCharacter) {
            this.oSelectedCharacter = oCharacter;
            if (lItemStatIDs.Count > 0) {
                do_RecalculateAllDPS();
                if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
            }
            if (bIsEquipped) if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
        }

        public void SetNonItemizedCharacter(Characters.ClassObjects.ocCharacter oCharacter) {
            oNonItemizedCharacter = oCharacter;
            bIsEquipped = false;
            Check_Equipped.Checked = false;
            do_RecalculateAllDPS();
            if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });

        }

        public void SetEquipped(bool bEquipped) {
            bIsEquipped = bEquipped;
            Check_Equipped.Checked = bEquipped;
        }

        public bool IsEquipped() {
            return bIsEquipped;
        }

        public void ForceDPSRecalculation() {
            do_RecalculateAllDPS();
            if (evItemStatsChanged != null) evItemStatsChanged(this, new ItemDPSEventArgs { fBaseDPS = this.fBaseDPS, fItemDPS = this.fItemDPS });
            if (bIsEquipped) if (evNonItemizedCharacterChanged != null) evNonItemizedCharacterChanged(this, do_CreateNewItemizedCharacter().ToCharacterEventArgs());
        }

    }

}
